using System;
using System.DirectoryServices;
using System.Security;
using System.Security.AccessControl;
using System.Security.Principal;
using System.Text;
using System.Web.Security;

namespace OrbitOne.SharePoint.Provision.WebParts
{
    public class ADProvisioning
    {
        /// <summary>
        /// Create a new OU in Active Directory
        /// </summary>
        /// <param name="name">Name of the new OU to create.</param>
        public static void CreateOrganizationalUnit(string name, string ldapConnectionString)
        {
            CreateOU(name, ldapConnectionString);
        }

        /// <summary>
        /// Delete an existing OU in Active Directory
        /// </summary>
        /// <param name="name">Name of the OU to delete.</param>
        public static void DeleteOrganizationalUnit(string name, string ldapConnectionString)
        {
            DeleteOU(name, ldapConnectionString);
        }

        /// <summary>
        /// Find an existing user anywhere in the container specified in the Active Directory connection string.
        /// </summary>
        /// <param name="userName">Logon name of user to find in Active Directory.</param>
        /// <returns>The email address of the found user, if present, otherwise, distinquished name of user.</returns>
        public static string FindUser(string userName, string ldapConnectionString)
        {

            DirectoryEntry user;
            string userInfo = String.Empty;

            // Get the LDAP path for the host container

            // Find the specified user
            user = FindObject("user", userName, ldapConnectionString);
            if (user == null) throw new Exception("User specified could not be found.");

            try
            {
                // Return the email address for this user
                userInfo = BuildUserXml(user);  //user.Properties["mail"].Value.ToString();
                if (string.IsNullOrEmpty(userInfo)) throw new Exception();
            }
            catch
            {
                // Return the distinquished name for this user
                userInfo = user.Properties["distinguishedName"].Value.ToString();
            }

            return userInfo;
        }

        /// <summary>
        /// Create a new user in Active Directory.
        /// </summary>
        /// <param name="firstName">First name of the new user to create.</param>
        /// <param name="lastName">Last name of the new user to create.</param>
        /// <param name="userName">Logon name of the new user to create.</param>
        /// <param name="password">Password of the new user to create.</param>
        /// <param name="email">Email address of the new user to create.</param>
        /// <param name="organizationalUnitName">OU in which to create the new user.</param>
        public static void CreateUser(string firstName, string lastName, string userName, string password, string email, string organizationalUnitName, string ldapConnectionString)
        {
            CreateUserObject(firstName, lastName, userName, password, email, organizationalUnitName, ldapConnectionString);
        }

        /// <summary>
        /// Delete a user in Active Directory.
        /// </summary>
        /// <param name="userName">User logon name of user to delete.</param>
        public static void DeleteUser(string userName, string ldapConnectionString)
        {
            DeleteUserObject(userName, ldapConnectionString);
        }

        /// <summary>
        /// Create a new group in Active Directory
        /// </summary>
        /// <param name="groupName">The name of the group to create</param>
        /// <param name="organizationalUnitName">The OU in which to create the new group.</param>
        public static void CreateGroup(string groupName, string organizationalUnitName, string ldapConnectionString)
        {
            CreateGroupObject(groupName, organizationalUnitName, ldapConnectionString);
        }

        /// <summary>
        /// Delete a group from Active Directory.
        /// </summary>
        /// <param name="groupName">The name of the group to delete.</param>
        public static void DeleteGroup(string groupName, string ldapConnectionString)
        {
            DeleteGroupObject(groupName, ldapConnectionString);
        }

        /// <summary>
        /// Add a user to a group in Active Directory
        /// </summary>
        /// <param name="userName">The logon name of the user to add to a specified group.</param>
        /// <param name="groupName">The name of the group to add the user into.</param>
        public static void AddUserToGroup(string userName, string groupName, string ldapConnectionString)
        {

            DirectoryEntry user;
            DirectoryEntry group;
            try
            {
                // Find the user object
                user = FindObject("user", userName, ldapConnectionString);
                if (user == null) throw new Exception("User object is null.");
            }
            catch (Exception userException)
            {
                throw new Exception("The user could not be found.", userException);
            }

            try
            {
                // Find the group object
                group = FindGroup(groupName, ldapConnectionString);
                if (group == null) throw new Exception("Group object is null.");
            }
            catch (Exception groupException)
            {
                throw new Exception("The group could not be found.", groupException);
            }

            // Add the specified user to the specified group
            AddUserToGroup(user, group);
        }

        /// <summary>
        /// Remove a user from an Active Directory group.
        /// </summary>
        /// <param name="userName">The logon name of the user to remove from the specified group.</param>
        /// <param name="groupName">The name of the group to remove the user from.</param>
        public static void RemoveUserFromGroup(string userName, string groupName, string ldapConnectionString)
        {

            DirectoryEntry user;
            DirectoryEntry group;
            try
            {
                // Find the user object
                user = FindObject("user", userName, ldapConnectionString);
                if (user == null) throw new Exception("User object is null.");
            }
            catch (Exception userException)
            {
                throw new Exception("The user could not be found.", userException);
            }

            try
            {
                // Find the group object
                group = FindGroup(groupName, ldapConnectionString);
                if (group == null) throw new Exception("Group object is null.");
            }
            catch (Exception groupException)
            {
                throw new Exception("The group could not be found.", groupException);
            }

            // Remove the specified user from the specified group
            RemoveUserFromGroup(user, group);

        }

        /// <summary>
        /// Configures the specified user or group for hosting read access on the specified OU
        /// </summary>
        /// <param name="organizationalUnitName">The name of the OU to configure access on</param>
        /// <param name="groupOrUserName">The group name or user logon to configure read access for</param>
        public static void SetReadAccess(string organizationalUnitName, string groupOrUserName, string ldapConnectionString)
        {

            DirectoryEntry deOU;
            DirectoryEntry deOther;
            try
            {
                // Get the OU object
                deOU = FindOU(organizationalUnitName, ldapConnectionString);
                if (deOU == null) throw new Exception("OU object is null.");
            }
            catch (Exception ouException)
            {
                throw new Exception("The organizational unit could not be found.", ouException);
            }

            // Find the group or user object
            deOther = FindObject("user", groupOrUserName, ldapConnectionString);
            if (deOther == null) deOther = FindGroup(groupOrUserName, ldapConnectionString);
            if (deOther == null)
            {
                // Maybe it's not the username - maybe it's the actual identityName
                AddHostingAccess(deOU, groupOrUserName);
            }
            else
            {
                // Since deOther is not NULL, then let's try to add hosting rules for this group or user on the specified OU
                AddHostingAccess(deOU, deOther);
            }
        }

        /// <summary>
        /// Remove read access on a specified OU for the Authenticated Users group
        /// </summary>
        /// <param name="organizationalUnitName">The OU to remove read access from.</param>
        // We can probably remove this - it's just for convenience since it's a comman task
        public static void RemoveAuthenticatedUsersAccess(string organizationalUnitName, string ldapConnectionString)
        {
            RemoveAllAccess(organizationalUnitName, @"NT AUTHORITY\Authenticated Users", ldapConnectionString);
        }

        /// <summary>
        /// Remove read access on a specifed OU for a specified user or group.
        /// </summary>
        /// <param name="organizationalUnitName">The OU to remove read access from.</param>
        /// <param name="groupOrUserName">The group name or user logon to remove read access.</param>
        public static void RemoveAllAccess(string organizationalUnitName, string groupOrUserName, string ldapConnectionString)
        {

            DirectoryEntry deOU;
            DirectoryEntry deOther;
            try
            {
                // Get the OU object
                deOU = FindOU(organizationalUnitName, ldapConnectionString);
                if (deOU == null) throw new Exception("OU object is null.");
            }
            catch (Exception ouException)
            {
                throw new Exception("The organizational unit could not be found.", ouException);
            }

            // Find the group or user object
            deOther = FindObject("user", groupOrUserName, ldapConnectionString);
            if (deOther == null) deOther = FindGroup(groupOrUserName, ldapConnectionString);
            if (deOther == null)
            {
                // Maybe it's not the username - maybe it's the actual identityName
                RemoveAccess(deOU, groupOrUserName);
            }
            else
            {
                // Since deOther is not NULL, then let's try to remove all rules for this group or user on the specified OU
                RemoveAccess(deOU, deOther);
            }

        }



        /// <summary>
        /// Sets the password for a specified user
        /// </summary>
        /// <param name="userName">User logon of the user to reset the password</param>
        /// <param name="newPassword">The new password for the user specified</param>
        public static void ResetPassword(string userName, string newPassword, string ldapConnectionString)
        {

            DirectoryEntry user;

            try
            {

                try
                {
                    // Find the user object
                    user = FindObject("user", userName, ldapConnectionString);
                    if (user == null) throw new Exception("User object is null.");
                }
                catch (Exception userException)
                {
                    throw new Exception("The user could not be found.", userException);
                }

                // Reset the user's password
                ResetPassword(user, newPassword);
            }
            catch (Exception exc)
            {
                throw exc;
            }
        }
        public static bool ValidateOldPassword(string userName, string oldPassword, string ldapConnectionString)
        {
            try
            {


                DirectoryEntry adsEntry = new DirectoryEntry(ldapConnectionString, userName, oldPassword);
                Object o = adsEntry.NativeObject;
                return true;
            }
            catch
            {
                return false;
            }

        }








        public static bool IsGroupExist(string groupName, string ldapConnectionString)
        {
            return FindGroup(groupName, ldapConnectionString) != null;
        }







        /// <summary>Get the Membership provider name from the web.config file</summary>
        /// <returns>Name of the membership provider</returns>
        private static string GetMembershipProviderName()
        {
            string providerName = string.Empty;

            // Get the provider name from the current Membership object
            providerName = Membership.Provider.Name;

            // Return the provider name
            return providerName;
        }


        /// <summary>
        /// Build an XML blob representing user data based on a User DirectoryEntry object.
        /// </summary>
        /// <param name="user">The user DirectoryEntry object to translate</param>
        /// <returns>An XML blob that includes much of the data from the original user object.</returns>
        private static string BuildUserXml(DirectoryEntry user)
        {
            StringBuilder userXml = new StringBuilder();
            string tempValue = String.Empty;

            userXml.Append("<user>");
            userXml.Append("<FirstName>");
            try
            {
                tempValue = user.Properties["givenName"].Value.ToString();
            }
            catch
            {
                tempValue = String.Empty;
            }
            userXml.Append(tempValue);
            userXml.Append("</FirstName>");
            userXml.Append("<LastName>");
            try
            {
                tempValue = user.Properties["sn"].Value.ToString();
            }
            catch
            {
                tempValue = String.Empty;
            }
            userXml.Append(tempValue);
            userXml.Append("</LastName>");
            userXml.Append("<UserLogon>");
            try
            {
                tempValue = GetIdentity(user);
            }
            catch
            {
                tempValue = String.Empty;
            }
            userXml.Append(tempValue);
            userXml.Append("</UserLogon>");
            userXml.Append("<Email>");
            try
            {
                tempValue = user.Properties["mail"].Value.ToString();
            }
            catch
            {
                tempValue = String.Empty;
            }
            userXml.Append(tempValue);
            userXml.Append("</Email>");
            userXml.Append("<DistinguishedName>");
            try
            {
                tempValue = user.Properties["distinguishedName"].Value.ToString();
            }
            catch
            {
                tempValue = String.Empty;
            }
            userXml.Append(tempValue);
            userXml.Append("</DistinguishedName>");
            userXml.Append("</user>");

            return userXml.ToString();
        }

        private static string GetDomainNameFromConnectionString(string connectionString)
        {
            StringBuilder result = new StringBuilder();
            string[] tempArr1 = connectionString.Split("/".ToCharArray());
            if (tempArr1.Length < 1)
                throw new ArgumentException("Invalid LDAP connection string.");

            string[] tempArr2 = tempArr1[tempArr1.Length - 1].Split(",".ToCharArray());
            if (tempArr2.Length < 1)
                throw new ArgumentException("Invalid LDAP connection string.");

            foreach (string s in tempArr2)
            {
                if (s.Trim().StartsWith("DC"))
                {
                    result.AppendFormat("{0}.", s.Substring(s.IndexOf('=') + 1));

                }
            }
            return result.ToString().TrimEnd(".".ToCharArray());

        }

        /// <summary>
        /// Creates a user in a given OU
        /// </summary>
        /// <param name="firstName">First name of user to create</param>
        /// <param name="lastName">Last name of user to create</param>
        /// <param name="userName">Login of user to create</param>
        /// <param name="password">Password of user to create</param>
        /// <param name="email">Email address of user to create</param>
        /// <param name="ouName">OU to create this user in</param>
        /// <param name="ldapConnectionString">LDAP connection str</param>
        /// <returns>DirectoryEntry represeting the newly created user</returns>
        private static DirectoryEntry CreateUserObject(string firstName, string lastName, string userName, string password, string email, string ouName, string ldapConnectionString)
        {
            const int ADS_UF_DONT_EXPIRE_PASSWD = 0x10000;
            DirectoryEntry parentOU;
            DirectoryEntries deChildren;
            DirectoryEntry user;

            // Get the hosting OU as the root node
            parentOU = FindOU(ouName, ldapConnectionString);

            deChildren = parentOU.Children;

            // Set the user parameters specified
            user = deChildren.Add("CN=" + firstName + " " + lastName, "user");
            user.Properties["samAccountName"].Add(userName);
            user.Properties["sn"].Add(lastName);
            user.Properties["givenName"].Add(firstName);
            user.Properties["displayName"].Add(firstName + " " + lastName);
            user.Properties["mail"].Add(email);
            user.Properties["userPrincipalName"].Add(userName + "@" + GetDomainNameFromConnectionString(ldapConnectionString));

            // Commit changes to AD
            user.CommitChanges();
            /*
            During commit, if the user already exists (the userlogon/samAccountName is already taken) error will be:
            System.DirectoryServices.DirectoryServicesCOMException was unhandled
            Message="The object already exists. (Exception from HRESULT: 0x80071392)"
             */

            try
            {
                // Set this new user's password

                user.Invoke("SetPassword", new object[] { password });
            }
            catch (Exception passwordException)
            {
                // If this fails, we should try to roll-back the user creation (delete this user)
                try
                {
                    DeleteUserObject(userName, ldapConnectionString);
                }
                catch
                {
                }

                // Perhaps we had a policy issue with this password
                throw new SecurityException("The password could not be set for this user.  Check to make sure it complies with the current password policy for Active Directory.", passwordException);
            }

            try
            {
                // Create a normal account and enable it - ADS_UF_NORMAL_ACCOUNT
                user.Properties["userAccountControl"].Value = 0x200;
                int val = (int)user.Properties["userAccountControl"].Value;
                user.Properties["userAccountControl"].Value = val | ADS_UF_DONT_EXPIRE_PASSWD;
                user.CommitChanges();
            }
            catch (Exception passwordException)
            {
                throw new Exception("The user was created, but could not be marked active.  Please delete this user and try to create it again.", passwordException);
                // TODO: should we just delete the user automatically if this happens?
            }

            return user;
        }

        /// <summary>
        /// Delete a user from Active Directory
        /// </summary>
        /// <param name="userName">User login for the user to be deleted</param>
        /// <param name="ldapConnectionString">LDAP connection string</param>
        private static void DeleteUserObject(string userName, string ldapConnectionString)
        {
            DirectoryEntries deChildren;
            DirectoryEntry user;

            // Find the user inside this parent group
            user = FindObject("user", userName, ldapConnectionString);
            if (user == null) throw new Exception("User object could not be found.");

            // Get the corresponding DirectoryEntries holding this user
            deChildren = user.Parent.Children;

            // Delete the user from AD
            deChildren.Remove(user);
        }

        /// <summary>
        /// Creates a new group in Active Directory under the OU specified
        /// </summary>
        /// <param name="groupName">Group name to create</param>
        /// <param name="ouName">OU to create this group in</param>
        /// <param name="ldapConnectionString">LDAP connection string</param>
        /// <returns>DirectoryEntry representing a newly created group</returns>
        private static DirectoryEntry CreateGroupObject(string groupName, string ouName, string ldapConnectionString)
        {
            DirectoryEntry parentOU;
            DirectoryEntry group;
            DirectoryEntries deChildren;

            // Get the hosting OU as the root node
            parentOU = FindOU(ouName, ldapConnectionString);

            // Get the DirectoryEntries in which to create this new OU
            deChildren = parentOU.Children;

            // Add the new group
            group = deChildren.Add("CN=" + groupName, "group");
            group.Properties["samAccountName"].Add(groupName);

            // Commit changes to AD
            group.CommitChanges();

            return group;
        }

        /// <summary>
        /// Deletes a group from Active Directory
        /// </summary>
        /// <param name="groupName">Name of the group to delete</param>
        /// <param name="ldapConnectionString">LDAP connection string</param>
        private static void DeleteGroupObject(string groupName, string ldapConnectionString)
        {
            DirectoryEntries deChildren;
            DirectoryEntry group;

            // Find the group
            group = FindGroup(groupName, ldapConnectionString);
            if (group == null) throw new Exception("Group object could not be found.");

            // Get the corresponding DirectoryEntries holding this group
            deChildren = group.Parent.Children;

            // Delete the user from AD
            deChildren.Remove(group);
        }

        /// <summary>
        /// Create an Organizational Unit in Active Directory
        /// </summary>
        /// <param name="ouName">Name of the OU to create</param>
        /// <param name="ldapConnectionString">LDAP connection string</param>
        /// <returns>DirectoryEntry object representing the newly created OU</returns>
        private static DirectoryEntry CreateOU(string ouName, string ldapConnectionString)
        {
            DirectoryEntry deLDAP;
            DirectoryEntries deChildren;
            DirectoryEntry deOU;

            // Get the parent container for this new OU
            deLDAP = new DirectoryEntry(ldapConnectionString);

            // Get the children collection for this container
            deChildren = deLDAP.Children;

            // Add the new OU to this container
            deOU = deChildren.Add("OU=" + ouName, "organizationalUnit");

            // Commit changes to AD
            deOU.CommitChanges();

            return deOU;
        }

        /// <summary>
        /// Delete an empty OU from Active Directory
        /// </summary>
        /// <param name="ouName">Name of the OU to delete</param>
        /// <param name="ldapConnectionString">LDAP connection string</param>
        private static void DeleteOU(string ouName, string ldapConnectionString)
        {
            //NOTE: this will only delete an empty OU, so you must delete all child items first
            DirectoryEntries deChildren;
            DirectoryEntry deOU;

            // Get the existing OU
            deOU = FindOU(ouName, ldapConnectionString);
            if (deOU == null) throw new Exception("Organizational Unit could not be found.");

            // Get the corresponding DirectoryEntries holding this OU
            deChildren = deOU.Parent.Children;

            // Remove the OU
            deChildren.Remove(deOU);
        }

        /// <summary>
        /// Adds a user to a group
        /// </summary>
        /// <param name="user">Name of user to add to a group</param>
        /// <param name="group">Name of the group to add a user to</param>
        private static void AddUserToGroup(DirectoryEntry user, DirectoryEntry group)
        {
            string userDN;

            // Get the user distinguished name
            userDN = user.Properties["distinguishedName"].Value.ToString();

            // Add this user as a member of this group
            group.Properties["member"].Add(userDN);

            // Save the group info
            group.CommitChanges();

        }

        /// <summary>
        /// Removes a user from a group
        /// </summary>
        /// <param name="user">Name of user to remove from the group</param>
        /// <param name="group">Name of the group to remove a user</param>
        private static void RemoveUserFromGroup(DirectoryEntry user, DirectoryEntry group)
        {
            string userDN;

            // Get the user distinguished name
            userDN = user.Properties["distinguishedName"].Value.ToString();

            // Remove this user from the member list of this group
            group.Properties["member"].Remove(userDN);

            // Save the group info
            group.CommitChanges();

        }

        /// <summary>
        /// Sets a new password for a user
        /// </summary>
        /// <param name="user">User login to set a specified password</param>
        /// <param name="newPassword">Password to set for this user</param>
        private static void ResetPassword(DirectoryEntry user, string newPassword)
        {
            try
            {
                // Set this new user's password
                user.Invoke("SetPassword", new object[] { newPassword });

                // Save the new password
                user.CommitChanges();
            }
            catch (Exception passwordException)
            {
                // Perhaps we had a policy issue with this password
                throw new SecurityException("The password could not be set for this user.  Check to make sure it complies with the current password policy for Active Directory.", passwordException);
            }
        }

        /// <summary>
        /// Remove all access roles for a given identity on this object
        /// </summary>
        /// <param name="deObj">Object with the access roles</param>
        /// <param name="identityName">Identity name to remove access</param>
        private static void RemoveAccess(DirectoryEntry deObj, string identityName)
        {
            ActiveDirectorySecurity deSecurity;
            AuthorizationRuleCollection allAccess;
            bool bRemoved = false;

            // Get the ActiveDirectorySecurity object
            deSecurity = deObj.ObjectSecurity;

            // Get all the access rules for this object in the form of NTAccounts
            allAccess = deSecurity.GetAccessRules(true, false, typeof(NTAccount));

            // Look at each rule
            foreach (AuthorizationRule rule in allAccess)
            {
                // Is this role's identity a match?
                if (rule.IdentityReference.Value == identityName)
                {
                    // Remove all access rules that match this user or group identity
                    deSecurity.RemoveAccess(rule.IdentityReference, AccessControlType.Allow);
                    // Commit the changes to the parent DirectoryEntry object
                    deObj.CommitChanges();
                    bRemoved = true;
                    break;
                }
            }

            // If no rule was found to match, raise an exception to tell the caller this was a mismatch
            if (!bRemoved) throw new Exception("No access rules were found matching the specified user or group.  No action was taken.");
        }

        /// <summary>
        /// Remove all access roles for a given identity on this object
        /// </summary>
        /// <param name="deObj">Object with the access roles</param>
        /// <param name="deRemoveObject">Object to remove access roles for</param>
        private static void RemoveAccess(DirectoryEntry deObj, DirectoryEntry deRemoveObject)
        {
            string identityName;

            // Create a SecurityIdentifier that matches the user or group specified in the object to remove access
            SecurityIdentifier removeSid = new SecurityIdentifier((byte[])deRemoveObject.Properties["objectSid"].Value, 0);

            // Greate an account matching the Security Identifier
            NTAccount account = (NTAccount)removeSid.Translate(typeof(NTAccount));

            // Get the string value of this account
            identityName = account.Value;

            // Remove the access rules for this user/group
            RemoveAccess(deObj, identityName);
        }

        /// <summary>
        /// Get the DOMAIN\name identity for an Active Directory object
        /// </summary>
        /// <param name="deObj">Object to get an identity</param>
        /// <returns>Identity for the specified object</returns>
        private static string GetIdentity(DirectoryEntry deObj)
        {
            string identityName;

            // Create a SecurityIdentifier that matches the user or group specified in the object to remove access
            SecurityIdentifier objSid = new SecurityIdentifier((byte[])deObj.Properties["objectSid"].Value, 0);

            // Greate an account matching the Security Identifier
            NTAccount account = (NTAccount)objSid.Translate(typeof(NTAccount));

            // Get the string value of this account
            identityName = account.Value;

            return identityName;
        }

        /// <summary>
        /// Adds the appropriate access for hosting read access to a user or group on a parent object (probably an OU)
        /// </summary>
        /// <param name="objToACL">Active Directory object to grant access on</param>
        /// <param name="identityName">Identity name of the object to be granted access to the objToACL</param>
        private static void AddHostingAccess(DirectoryEntry objToACL, string identityName)
        {
            IdentityReference idRef;

            // Create an NTAccount based on the supplied identityName
            NTAccount account = new NTAccount(identityName);

            // Translate this NTAccount into a SecurityIdentifier
            idRef = (IdentityReference)account.Translate(typeof(SecurityIdentifier));

            // Add the appropriate access for this SecurityIdentifier
            AddHostingAccess(objToACL, idRef);
        }

        /// <summary>
        /// Adds the appropriate access for hosting read access to a user or group on a parent object (probably an OU)
        /// </summary>
        /// <param name="objToACL">Active Directory object to grant access on</param>
        /// <param name="objToGiveAccess">Active Directory object to be granted access to the objToACL</param>
        private static void AddHostingAccess(DirectoryEntry objToACL, DirectoryEntry objToGiveAccess)
        {
            // Create a SecurityIdentifier that matches the user or group specified in the object to give access to
            SecurityIdentifier newSid = new SecurityIdentifier((byte[])objToGiveAccess.Properties["objectSid"].Value, 0);

            // Add the appropriate access for this Identity
            AddHostingAccess(objToACL, (IdentityReference)newSid);
        }

        /// <summary>
        /// Adds the appropriate access for hosting read access to a user or group on a parent object (probably an OU)
        /// </summary>
        /// <param name="objToACL">Active Directory object to grant access on</param>
        /// <param name="idRef">IdentityReference of the object to be granted access to the objToACL</param>
        private static void AddHostingAccess(DirectoryEntry objToACL, IdentityReference idRef)
        {

            ActiveDirectorySecurity deSecurity;
            ActiveDirectoryAccessRule newRule1;
            ActiveDirectoryAccessRule newRule2;

            // Get the ActiveDirectorySecurity object for this parent DirectoryEntry
            deSecurity = objToACL.ObjectSecurity;

            // List Contents, Read All Permissions, Read Permissions for this object and all child objects
            newRule1 = new ActiveDirectoryAccessRule(idRef, ActiveDirectoryRights.ListChildren | ActiveDirectoryRights.ReadProperty | ActiveDirectoryRights.ReadControl, AccessControlType.Allow, ActiveDirectorySecurityInheritance.SelfAndChildren);

            // List Object for this object only
            newRule2 = new ActiveDirectoryAccessRule(idRef, ActiveDirectoryRights.ListObject, AccessControlType.Allow, ActiveDirectorySecurityInheritance.None);

            // Add these rules to the ActiveDirectorySecurity object
            deSecurity.AddAccessRule(newRule1);
            deSecurity.AddAccessRule(newRule2);

            // Commit changes to the parent object
            objToACL.CommitChanges();

        }



        /// <summary>
        /// Find a group object in Active Directory
        /// </summary>
        /// <param name="groupName">Group name</param>
        /// <param name="ldapConnectionString">LDAP connection string</param>
        /// <returns>DirectoryEntry object representing this group</returns>
        private static DirectoryEntry FindGroup(string groupName, string ldapConnectionString)
        {
            return FindObject("group", groupName, ldapConnectionString);
        }

        public static bool IsValidConnectionString(string ldapConnectionString)
        {
            DirectoryEntry testObj = new DirectoryEntry(ldapConnectionString);
            try
            {
                string temp = testObj.Name;
            }
            catch
            {
                return false;
            }

            return true;
        }

        public static bool IsOrganisationUnitExist(string ou, string ldapConnectionString)
        {
            if (FindOU(ou, ldapConnectionString) == null)
            {
                return false;
            }
            else
                return true;
        }
        /// <summary>
        /// Find an OU object in Active Directory
        /// </summary>
        /// <param name="ouName">Name of the OU to find</param>
        /// <param name="ldapConnectionString">LDAP connection string</param>
        /// <returns>DirectoryEntry object representing this OU</returns>
        private static DirectoryEntry FindOU(string ouName, string ldapConnectionString)
        {
            DirectoryEntry testObj;
            DirectoryEntry foundOU;
            string revisedConnectionString = String.Empty;

            try
            {
                // Try to look for the OU in this parent container
                revisedConnectionString = ldapConnectionString.Insert(ldapConnectionString.LastIndexOf("/") + 1, "OU=" + ouName + ",");
            }
            catch
            {
                // Could not find the OU at this level - or the connection string was not as we expected (maybe a slash at the end?)
            }

            foundOU = new DirectoryEntry(revisedConnectionString);

            try
            {
                // Is this a valid DirectoryEntry (pointing to an OU) - NOTE: could also check the Name - make sure it's "organizationalUnit"
                testObj = foundOU.SchemaEntry;
            }
            catch
            {
                // May not be a valid DirectoryEntry
                foundOU = null;
            }

            return foundOU;
        }

        /// <summary>
        /// Find an object in Active Directory
        /// </summary>
        /// <param name="objClass">The type of object to look for</param>
        /// <param name="samAccountName">name of the object</param>
        /// <param name="ldapConnectionString">LDAP connection string</param>
        /// <returns>DirectoryEntry object matching this search</returns>
        private static DirectoryEntry FindObject(string objClass, string samAccountName, string ldapConnectionString)
        {
            DirectoryEntry objToFind;
            SearchResult foundStuff;
            DirectorySearcher searcher = new DirectorySearcher();

            searcher.SearchRoot = new DirectoryEntry(ldapConnectionString);
            searcher.Filter = "(&(objectClass=" + objClass + ")(samAccountName=" + samAccountName + "))";

            foundStuff = searcher.FindOne();

            if (foundStuff != null)
            {
                objToFind = new DirectoryEntry(foundStuff.Path);

                // This could be an invalid DirectoryEntry (is there a better test?)
                if (objToFind.SchemaEntry == null)
                {
                    objToFind = null;
                }
            }
            else
            {
                objToFind = null;
            }

            return objToFind;
        }
    }
}